/**
 * 
 */
package br.embedded.ufcg.rmi;

import java.net.MalformedURLException;
import java.rmi.Naming;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;
import java.util.List;

import org.jgrapht.Graph;
import org.jgrapht.graph.DefaultEdge;

import br.edu.ufcg.embedded.mysocial.GraphCacheManager;

/**
 * @author daniel
 *
 */
public class Client
{
	private static int NUMBER_OF_THREADS;
	private static int MAX_RECORDS;
	private static int MAX_LEVELS;
	private static String SERVER_URL;
	private static String BULK_PATH;

	private static Graph<String, DefaultEdge> graph;
	private static List<String> jobList;
	
	public static String hostname;
	private static StatisticsInfo statisticsInfo; 
	
	private static final long SLEEP_TIME = 10 * 1000;

	public static void main(String[] args)
	{
		if (args != null && args.length == 6)
		{
			try
			{
				SERVER_URL = args[0];
				NUMBER_OF_THREADS = Integer.parseInt(args[1]);
				MAX_RECORDS = Integer.parseInt(args[2]);
				MAX_LEVELS = Integer.parseInt(args[3]);
				BULK_PATH = args[4];
				hostname = args[5];
			}
			catch (Exception e) {
				e.printStackTrace();
			}

			checkConnection();
			register();
			read();
			getJobList();

			GraphCacheManager manager = new GraphCacheManager(graph, jobList, MAX_LEVELS, NUMBER_OF_THREADS , MAX_RECORDS, BULK_PATH);

			statisticsInfo = new StatisticsInfo(hostname, graph.vertexSet().size(), graph.edgeSet().size(),
					MAX_LEVELS, NUMBER_OF_THREADS);

			graph = null;
			jobList = null;

			System.gc();

			Long t1 = System.currentTimeMillis();
			manager.run();
			Long t2 = System.currentTimeMillis();

			statisticsInfo.setElapsedTime(t2 - t1);

			sendStatisticsInfo();

		}
		else
			System.out.println("ClientProcess: Invalid parameters input.");
	}

	private static void read()
	{
		Process process;

		try {
			process = (Process) Naming.lookup(SERVER_URL);
			
			graph = process.getGraph();
			System.out.println("ClientProcess: a Graph with " 
					+ graph.vertexSet().size() + " nodes and " + graph.edgeSet().size() 
					+ " edges was received successfully.");
		}
		catch(MalformedURLException e )
		{
			System.out.println();
			System.out.println("MalformedURLException: " + e.toString());
		}  
		catch(RemoteException e )
		{ 
			System.out.println();
			System.out.println("RemoteException: " + e.toString());
		}  
		catch(NotBoundException e )
		{
			System.out.println();
			System.out.println("NotBoundException: " + e.toString()); 
		}
	}
		
	private static void checkConnection()
	{
		boolean ready = false;
		String rmiServer = SERVER_URL.substring(0, SERVER_URL.lastIndexOf("/"));
		
		while (!ready)
		{
			try {
				 String[] list = Naming.list(rmiServer);
				 
				 if (!find(list, SERVER_URL.substring(4, SERVER_URL.length())))
					 doSleep();
				 else
					 ready = true;
				 
				 list = null;
			}
			catch (RemoteException e) {
				if (e.getCause() instanceof java.net.ConnectException) {
					ready = false;
					doSleep();
				}
			}
			catch (MalformedURLException e) {
				System.out.println("Client Fatal error(1). Cause: " + e.getMessage());
				System.exit(1);
			} 
		}
		System.out.println("Client will connect...");
	}
	
	private static boolean find(String[] list, String entry)
	{
		if (list == null || list.length == 0)
			return false;
			
		for (int i = 0; i < list.length; i++) {
			if (list[i].equalsIgnoreCase(entry))
				return true;
		}
		return false;
	}
	
	private static void doSleep()
	{
		try {
			System.out.print(".");
			Thread.sleep(SLEEP_TIME);
		} catch (InterruptedException e1) {
			e1.printStackTrace();
		}
	}

	private static void register()
	{
		Process process;
		
		try {
			process = (Process) Naming.lookup(SERVER_URL);
			process.register(hostname);
		} catch(MalformedURLException e )
		{
			System.out.println();
			System.out.println("MalformedURLException: " + e.toString());
		}  
		catch(RemoteException e )
		{
			System.out.println();
			System.out.println("RemoteException: " + e.toString());
		}  
		catch(NotBoundException e )
		{
			System.out.println();
			System.out.println("NotBoundException: " + e.toString()); 
		}
	}
	
	private static void sendStatisticsInfo()
	{
		Process process;
		
		try {
			process = (Process) Naming.lookup(SERVER_URL);
			process.setStatisticsInfo(statisticsInfo);
		} catch(MalformedURLException e )
		{
			System.out.println();
			System.out.println("MalformedURLException: " + e.toString());
		}  
		catch(RemoteException e )
		{ 
			System.out.println();
			System.out.println("RemoteException: " + e.toString());
		}  
		catch(NotBoundException e )
		{
			System.out.println();
			System.out.println("NotBoundException: " + e.toString()); 
		}
	}
	
	private static void getJobList()
	{
		Process process;
		
		try {
			process = (Process) Naming.lookup(SERVER_URL);
			
			jobList = process.getJobList(hostname);
			System.out.println("Size of workload: " + jobList.size());
			
		} catch(MalformedURLException e )
		{
			System.out.println();
			System.out.println("MalformedURLException: " + e.toString());
		}  
		catch(RemoteException e )
		{ 
			System.out.println();
			System.out.println("RemoteException: " + e.toString());
		}
		catch(NotBoundException e )
		{
			System.out.println();
			System.out.println("NotBoundException: " + e.toString()); 
		}
	} 
}